
import os,time,sys
from ftplib import FTP
from time import sleep
import pathlib
import time
import serial
from time import sleep
from struct import *
import binascii
import os
import re


class MyFtp:
    ftp = FTP()
    
    def __init__(self, host, port=2100):
        self.ftp.set_debuglevel(0)
        self.ftp.connect(host, port)

    def login(self, username, pwd):
        self.ftp.set_debuglevel(2)  # 打开调试级别2，显示详细信息
        self.ftp.login(username, pwd)
        # print(self.ftp.welcome)

    def downloadFile(self, localpath, remotepath, filename):
        os.chdir(localpath)  # 切换工作路径到下载目录
        self.ftp.cwd(remotepath)  # 要登录的ftp目录
        self.ftp.nlst()  # 获取目录下的文件
        file_handle = open(filename, "wb").write  # 以写模式在本地打开文件
        self.ftp.retrbinary('RETR %s' % os.path.basename(filename), file_handle, blocksize=1024)  # 下载ftp文件
        # ftp.delete（filename）  # 删除ftp服务器上的文件

    def upload_file(self, remotepath, localpath):
        bufsize = 1024
        fp = open(localpath, 'rb')

        self.ftp.storbinary('STOR ' + remotepath, fp, bufsize)
        self.ftp.set_debuglevel(0)
        fp.close()

    def close(self):
        self.ftp.set_debuglevel(0)  # 关闭调试
        self.ftp.quit()


class scan_ftp():

    def __init__(self):
        self.ftp = FTP()
        timeout = 30
        port = 21
        self.ftp.connect('192.168.100.101', 21, timeout)
        self.ftp.login('anonymous', '')
        self.ftp.cwd('/baiyunpeng/smoke_test/daily_serial_check')

    def get_all_file(self):
        filelist = []
        self.ftp.retrlines('NLST', filelist.append)
        outlist = [x for x in filelist if '.bin' in x]
        return filelist

    def ask_time(self, file):
        L = list(self.ftp.sendcmd('MDTM ' + file))
        dir_t = L[4] + L[5] + L[6] + L[7] + '-' + L[8] + L[9] + '-' + L[10] + L[11] + ' ' + L[12] + L[13] + ':' + L[
            14] + L[15] + ':' + L[16] + L[17]
        timeArray = time.strptime(dir_t, "%Y-%m-%d %H:%M:%S")
        timeStamp = int(time.mktime(timeArray))
        return timeStamp

    def give_biggest(self):
        all_file = self.get_all_file()
        all_time = []
        for (i, file) in enumerate(all_file):
            time_single = self.ask_time(file)
            all_time.append(time_single)
        biggest = max(all_time)
        num = all_time.index(biggest)
        return all_file[num]


def timestamp():
    stamp = time.strftime('%Y-%m-%d_%H:%M:%S', time.localtime(time.time()))
    return stamp


def get_newest_bin_OnFtpServer():
    a = scan_ftp()
    filename = a.give_biggest()

    obj = pathlib.PurePosixPath(filename)
    pure_name = obj.stem

    bin_name = pure_name + '.bin'
    ini_name = pure_name + '.ini'

    nnn = 'The Newest Bin is [%s]' % bin_name
    print("\033[1;92;40m%s\033[0m" % nnn)

    localpath = '.'

    ftp = MyFtp('192.168.100.101', 21)
    ftp.login('anonymous', '')
    print("\033[1;92;40m%s\033[0m" % "========== download bin file from FTP ===========")
    ftp.downloadFile(localpath, '/baiyunpeng/smoke_test/daily_serial_check', bin_name)
    ftp.downloadFile(localpath, '/baiyunpeng/smoke_test/daily_serial_check', ini_name)
    ftp.close()
    return pure_name


def power_off_and_on(power_port):
    c1 = [0xA0, 0x01, 0x01, 0xA2]
    c2 = [0xA0, 0x01, 0x00, 0xA1]

    ss = serial.Serial(power_port, baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1)
    if ss.is_open:
        ss.write(c1)
        sleep(0.5)
        ss.write(c2)
    print("\033[1;91;40m%s\033[0m" % "==[EVB reset]==")


def StrtoHexlist(instr):
    mm = re.findall(r'.{2}', instr)
    nn = [int(x, 16) for x in mm]
    return nn


def sendbin(ser_obj, ser_baudrate, file_obj, begin_hint, success_hint, read_step_size, sleep_dividend, sleep_time):
    nnn = '[==>]' + begin_hint
    print("\033[1;96;40m%s\033[0m" % nnn)
    ser_obj.baudrate = ser_baudrate
    i = 0
    while 1:
        c = file_obj.read(read_step_size)
        ssss = str(binascii.b2a_hex(c))[2:-1]
        if not c:
            break
        ser_obj.write(bytes().fromhex(ssss))  # 将16进制转换为字节
        if i % sleep_dividend == 0:
            time.sleep(sleep_time)
        i += 1
    nnn = '[<==]' + success_hint
    print("\033[1;93;40m%s\033[0m" % nnn)


def sendUpgradeRequest(ser_obj, target_bin_path):
    burn_cmd1 = [0xA5, 0x5A, 0xA5, 0x5A, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x01, 0x01]
    burn_cmd3 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

    binzise = os.path.getsize(target_bin_path)
    hexstr = "%08x" % binzise
    cmd2 = StrtoHexlist(hexstr)
    final_cmd = burn_cmd1 + cmd2 + burn_cmd3
    ser_obj.write(final_cmd)
    print("\033[1;92;40m%s\033[0m" % "[Send Upgrade Request to EVB..]")


def SendTx21_waitStr(ser_obj, wait_str, begin_hint, success_hint, debug=True):
    tx21_cmd = [0x54, 0x58, 0x32, 0x31]
    nnn = '[==>]' + begin_hint
    print("\033[1;96;40m%s\033[0m" % nnn)
    while 1:
        ser_obj.write(tx21_cmd)
        tdata = ser_obj.read()
        data_left = ser_obj.inWaiting()
        tdata += ser_obj.read(data_left)
        if debug:
            print([tdata])
        t_str = tdata.decode('utf-8', 'replace')
        if wait_str in t_str:
            break
    nnn = '[<==]' + success_hint
    print("\033[1;93;40m%s\033[0m" % nnn)
    
def waitStr(ser_obj, wait_str, begin_hint, success_hint, debug=True):
    nnn = '[==>]' + begin_hint
    print("\033[1;96;40m%s\033[0m" % nnn)
    while 1:
        tdata = ser_obj.read()
        data_left = ser_obj.inWaiting()
        tdata += ser_obj.read(data_left)
        if debug:
            print([tdata])
        t_str = tdata.decode('utf-8', 'replace')
        if wait_str in t_str:
            break
    nnn = '[<==]' + success_hint
    print("\033[1;93;40m%s\033[0m" % nnn)
    return t_str


def upgrade_evb(target_bin_path):
    start = time.time()
    file1 = open('/home/pi/jks_space/backup/snd_boot_1_5M.bin', 'rb')
    file2 = open('/home/pi/jks_space/backup/PB_UART_1_5M.bin', 'rb')

    evb_serial_port = '/dev/ttyUSB1'
    power_serial_port= '/dev/ttyUSB0'


    # target_bin_path = 'cn_cmd_sp9.bin'
    target_bin = open(target_bin_path, 'rb')

    evb_s = serial.Serial(evb_serial_port, baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=1)

    count = evb_s.inWaiting()
    sleep(2)
    power_off_and_on(power_serial_port)

    # 开机等UA，周期发TX21，等ZZ
    waitStr(evb_s, 'UA', 'Now Waiting for UA...', 'Receive UA OK !!')
    SendTx21_waitStr(evb_s, 'ZZ', 'Now Waiting for ZZ...', 'Receive ZZ OK !!')

    # Send Load 1
    sendbin(evb_s, 115200, file1, 'Send Load1...', 'Send Load1 OK !!', 8, 512, 0.0005)
    sleep(0.009)

    # Send Load 2
    sendbin(evb_s, 1500000, file2, 'Send Load2...', 'Send Load2 OK !!', 16, 512, 0.0005)
    waitStr(evb_s, 'is done', 'Now Waiting for Load2 Init ACK...', 'Receive Load2 Init ACK OK !! ')

    # 发送升级命令
    sleep(0.05)
    sendUpgradeRequest(evb_s, target_bin_path)
    waitStr(evb_s, 'Erase', 'Now Waiting for Erase Suc Ack...', 'Receive Erase Suc Ack OK !! ', False)

    # 发送target bin
    sleep(0.01)
    sendbin(evb_s, 1500000, target_bin, "Send Bin file[%s]" % target_bin_path, 'Send bin Done', 16, 512, 0.0005)
    waitStr(evb_s, 'board', 'Now Waiting for Upgrade Suc Ack...', 'Receive Upgrade Suc Ack OK !!')

    power_off_and_on(power_serial_port)
    evb_s.baudrate = 115200
    vv = waitStr(evb_s, 'version', 'Now Waiting for Power On Print...', 'Receive Power On Print OK !!')
    vv_str = str(vv).replace('\\r',' ').replace('\\n',' ').replace('\r',' ').replace('\n',' ')
    s_obj = re.search(r'version (.*?) ', vv_str)
    nnn = 'Get Version String is [%s]' % s_obj.group(1)
    print("\033[1;93;40m%s\033[0m" % nnn)

    end = time.time()
    print("Send Bin Cost time: %s seconds" % (end - start))


if __name__ == '__main__':
    new_name = get_newest_bin_OnFtpServer()
    os.rename(new_name + '.ini',"bin.ini")
    upgrade_evb(new_name + '.bin')

